//! 过滤白明白中间件，首先查看header中是否存在origin，如果不存在则返回未授权。
//! 如果存在，查看origin中的uri是否在白名单中，不存在返回未授权。

use crate::middleware::{pin_box_future, MiddleError, PinBoxFuture};
use axum::{
    http::{header, Request, StatusCode},
    response::{IntoResponse, Response},
    BoxError,
};

use std::task::{Context, Poll};
use tower::{Layer, Service};

#[derive(Clone)]
pub struct FilterWhiteListLayer {
    white_list: Vec<String>,
}

impl FilterWhiteListLayer {
    pub fn new(white_list: Vec<String>) -> Self {
        FilterWhiteListLayer { white_list }
    }
}

impl<S> Layer<S> for FilterWhiteListLayer {
    type Service = FilterWhiteList<S>;

    fn layer(&self, inner: S) -> Self::Service {
        FilterWhiteList {
            inner,
            white_list: self.white_list.clone(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct FilterWhiteList<S> {
    inner: S,
    white_list: Vec<String>,
}

impl<S, B> Service<Request<B>> for FilterWhiteList<S>
where
    S: Service<Request<B>>,
    S::Future: Send + 'static,
    S::Error: Into<BoxError>,
    S::Response: IntoResponse,
    B: Send + 'static,
{
    type Response = Response;
    type Error = BoxError;
    type Future = PinBoxFuture<Result<Self::Response, Self::Error>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx).map_err(Into::into)
    }

    fn call(&mut self, req: Request<B>) -> Self::Future {
        let origin = req.headers().get(header::ORIGIN).cloned();
        let req = self.inner.call(req);
        let list = self.white_list.clone();
        pin_box_future(async move {
            if origin.is_none() {
                return Err(MiddleError(StatusCode::UNAUTHORIZED, "未授权".to_string()).into());
            }
            let origin = origin.unwrap();
            let origin = origin.to_str();
            if let Err(e) = origin {
                tracing::error!("header中origin转换字符串错误:{}", e);
                return Err(
                    MiddleError(StatusCode::BAD_REQUEST, "非utf8编码格式请求".to_string()).into(),
                );
            }
            let origin = origin.unwrap();
            for l in list {
                if l.as_str() == origin {
                    let res = req
                        .await
                        .map(IntoResponse::into_response)
                        .map_err(Into::into);
                    return res;
                }
            }
            Err(MiddleError(StatusCode::UNAUTHORIZED, "未授权".to_string()).into())
        })
    }
}
